package cn.itcast.demo;

import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class LuceneIndexQueryText {

    @Test
    public void testQueryIndex() throws IOException, ParseException {



        //把用户的需求带入 :::索引写入的分词器一定要和查询的分词器一致
        QueryParser queryParser = new QueryParser("title",new IKAnalyzer());

        Query query = queryParser.parse("谷歌");//谷歌地图，谷歌，地图

        search(query);

    }

    @Test
    public void testQueryMultiFieldIndex() throws IOException, ParseException {
        //把用户的需求带入 :::索引写入的分词器一定要和查询的分词器一致
        // QueryParser queryParser = new QueryParser("title",new IKAnalyzer());
        MultiFieldQueryParser queryParser = new MultiFieldQueryParser(new String[]{"id","title"},new IKAnalyzer());

        Query query = queryParser.parse("3");//谷歌地图，谷歌，地图
        search(query);

    }

    @Test
    public void testTermQuery() throws IOException, ParseException {

        //定义term词条查询
        Query query = new TermQuery(new Term("title","facebook"));

        search(query);
    }

    @Test
    public void testWildcardQuery() throws IOException, ParseException {

        //定义
        Query query = new WildcardQuery(new Term("title","谷歌?"));

        search(query);
    }


    @Test
    public void testFuzzyQuery() throws IOException, ParseException {

        //定义限定他的最大编辑距离（改几次），默认是2，取值范围是0-2
        Query query = new FuzzyQuery(new Term("title","facebooc"),1);

        search(query);
    }

    /**
     * 数值范围查询
     * @throws IOException
     * @throws ParseException
     */
    @Test
    public void testNumericQuery() throws IOException, ParseException {

        //相当于把2做了转义，2----》口口
        //5个参数分别表示查询的字段，最小范围值，最大范围值，是否包含左边界
        Query query = NumericRangeQuery.newLongRange("id",2L,4L,true,true);

        search(query);
    }


    /**
     * 组合查询，根据多个条件生成最后的结果
     * MUST VS MUST   &&  交集
     * SHOULD VS SHOULD    || 并集
     *
     * MUST_NOT ,,MUST  VS  MUST_NOT
     * @throws IOException
     * @throws ParseException
     */
    @Test
    public void testBooleanQuery() throws IOException, ParseException {

        //相当于把2做了转义，2----》口口
        //5个参数分别表示查询的字段，最小范围值，最大范围值，是否包含左边界
        Query query1 = NumericRangeQuery.newLongRange("id",2L,4L,true,true);
        Query query2 = NumericRangeQuery.newLongRange("id",1L,3L,true,true);

        BooleanQuery query = new BooleanQuery();
        //给组合查询条件添加子条件
        query.add(query1, BooleanClause.Occur.SHOULD);
        query.add(query2, BooleanClause.Occur.SHOULD);

        search(query);
    }


    private void search(Query query) throws IOException, ParseException {
        //先去索引库中加载所有的数据
        Directory directory = FSDirectory.open(new File("indexDir"));

        //加载索引数据到内存
        IndexReader indexReader = DirectoryReader.open(directory);

        //把加载到的索引数据放到内存中，以供查询

        //索引的检索
        IndexSearcher searcher = new IndexSearcher(indexReader);



        //query 查询条件，n表示要查询多少个，手机100万个n是5表示只显示5个
        TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE);

        //命中的个数，实际展示的个数取决于命中的个数和用户设置的需求的个数如果命中的大于需求的，以需求的为准，如果命中的小于需求的则以命中的为准
        int totalHits = topDocs.totalHits;

        System.out.println("总共命中了 = " + totalHits+" 个");

        //获取到得分文档的数组，不过数组中只包含了文档的编号和文档得分，得分用来排序
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;

        for (ScoreDoc scoreDoc : scoreDocs) {
            System.out.println("====================================");
            //文档的id
            int docId = scoreDoc.doc;
            //文档的得分
            float score = scoreDoc.score;

            Document doc = searcher.doc(docId);
            String id = doc.get("id");
            String title = doc.get("title");

            System.out.println("当前文档的得分为："+score+" id为："+id+" title为:"+title);
        }
    }
}
